//
//  CustomPresentationController.swift
//  CustomTransitions
//
//  Created by fuyoufang on 2021/10/12.
//

import UIKit

class CustomPresentationController: UIPresentationController {
    struct Containt {
        static let cornerRadius: CGFloat = 16
    }
    
    var dimmingView: UIView?
    var presentationWrappingView: UIView?
    
    override init(presentedViewController: UIViewController, presenting presentingViewController: UIViewController?) {
        super.init(presentedViewController: presentedViewController, presenting: presentingViewController)
        
        #warning("modalTransitionStyle 这个属性的用法？")
        presentedViewController.modalPresentationStyle = .custom
    }
    
    
    override var presentedView: UIView? {
        return self.presentationWrappingView
    }
    
    override func presentationTransitionWillBegin() {
        #warning("Apple 代码中没有调用 super 方法")
        super.presentationTransitionWillBegin()
        
        let presentationWrappingView = UIView().then {
            $0.frame = frameOfPresentedViewInContainerView
            $0.layer.do {
                $0.shadowOpacity = 0.44
                $0.shadowRadius = 13
                $0.shadowOffset = CGSize(width: 0, height: -6)
            }
        }
        self.presentationWrappingView = presentationWrappingView
        
        // 设置 frame 的时候，需要设置 autoresizingMask
        // 否则在旋转的过程中，会有问题
        // 或者这里可以使用 AutoLayout
        let presentationRoundedCornerView = UIView().then {
            $0.frame = presentationWrappingView.bounds
                .inset(by: UIEdgeInsets(top: 0,
                                        left: 0,
                                        bottom: -Containt.cornerRadius,
                                        right: 0))
            $0.autoresizingMask = [.flexibleWidth, .flexibleHeight]
            $0.layer.cornerRadius = Containt.cornerRadius
            $0.clipsToBounds = true
        }
        presentationWrappingView.addSubview(presentationRoundedCornerView)
        
        let presentedViewControllerWrapperView = UIView()
            .then {
                $0.frame = presentationRoundedCornerView.bounds
                    .inset(by: UIEdgeInsets(top: 0,
                                            left: 0,
                                            bottom: Containt.cornerRadius,
                                            right: 0))
                $0.autoresizingMask = [.flexibleWidth, .flexibleHeight]
            }
        
        presentationRoundedCornerView.addSubview(presentedViewControllerWrapperView)
        
        if let presentedView = super.presentedView {
            presentedView.do {
                $0.frame = presentationWrappingView.bounds
                $0.autoresizingMask = [.flexibleWidth, .flexibleHeight]
            }
            presentedViewControllerWrapperView.addSubview(presentedView)
        }
        
        let dimmingView = UIView().then {
            $0.alpha = 0
            $0.backgroundColor = UIColor(white: 0, alpha: 0.4)
            $0.frame = containerView?.bounds ?? .zero
            let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapDimmingView))
            $0.addGestureRecognizer(gestureRecognizer)
        }
        containerView?.addSubview(dimmingView)
        self.dimmingView = dimmingView
        
        if let transitionCoordinator = self.presentingViewController.transitionCoordinator {
            transitionCoordinator.animate { context in
                dimmingView.alpha = 1
            } completion: { context in
                
            }
        }
    }
    
    @objc func tapDimmingView() {
        self.presentedViewController.dismiss(animated: true, completion: nil)
    }
    
    override func presentationTransitionDidEnd(_ completed: Bool) {
        super.presentationTransitionDidEnd(completed)
        
        if !completed {
            self.dimmingView = nil
            self.presentationWrappingView = nil
        }
    }
    
    /// 当屏幕旋转的时候，系统会调用此方法，获取 presentedViewController view 的 size，
    /// 然后通过 viewWillTransition(to size:, with coordinator:) 告诉 view controller 即将转换到新的 size。
    /// Apple 官方 demo 中，如果 container 是 presentedViewController 时，
    /// 直接返回 presentedViewController 的 preferredContentSize。
    /// 但是在 frameOfPresentedViewInContainerView 中，只使用了 presentedViewController 的 preferredContentSize 的 height。
    /// 会导致，presentedViewController 的 viewWillTransition(to size:, with coordinator:) 方法中，接收到的 size，并不是自己真正最后的 size.
    ///
    /// 当内容容器先子容器发送 viewWillTransitionToSize:withTransitionCoordinator:时，
    /// 它将调用这个方法来确定发送它们的大小。
    /// 如果返回的大小与子容器当前的大小相同，
    /// 则viewWillTransitionToSize:withTransitionCoordinator:将不会被调用。
    ///
    override func size(forChildContentContainer container: UIContentContainer, withParentContainerSize parentSize: CGSize) -> CGSize {
        
        if let viewController = container as? UIViewController,
            viewController == self.presentedViewController {
            debugPrint("size for presentedViewController")
#warning(
"""
Apple 官方 demo 中，此处返回 viewController.preferredContentSize
""")
//            return viewController.preferredContentSize
            
#warning("""
此处的 parentSize 可能是 containerView 的 size。有没有其他可能？
苹果的文档显示为：

The size of the parent view controller.

下面一段话应该是错的，但是测试的时候，parentSize 可能是一个奇怪的值
--并不是屏幕的大小，也不是 containerView 的大小。所以也不能根据 parentSize 来确定 presentedViewController view 的 size--
""")
            return CGSize(width: self.containerView?.bounds.width ?? viewController.preferredContentSize.width,
                          height: viewController.preferredContentSize.height)

        } else {
            return super.size(forChildContentContainer: container, withParentContainerSize: parentSize)
        }
    }
    
    override var frameOfPresentedViewInContainerView: CGRect {
        debugPrint("frameOfPresentedViewInContainerView")
        guard let containerView = containerView else {
            return .zero
        }
        
        let size = size(forChildContentContainer: self.presentedViewController,
                        withParentContainerSize: containerView.bounds.size)
        #warning(
        """
        Apple 官方 demo 中，返回的 Rect 的 width 为 containerView.bounds.size.width,
        而不是 presentedViewController 的 preferredContentSize 的 size.width，
        只使用了 preferredContentSize 的 height。
        """)
        
//        let presentedViewControllerFrame = containerView.bounds
//            .with {
//                $0.origin.y = containerView.bounds.maxY - size.height
//                $0.size.height = size.height
//            }
//
//        return presentedViewControllerFrame

        // 但是感觉直接使用 preferredContentSize 更加合理
        // 系统会通知 presentedViewController 即将旋转，顺序为：
        // 1. willTransition(to newCollection:, with coordinator:)
        // 2. viewWillTransition(to size:, with coordinator:)
        // 然后调用开始新的布局，新的布局会用到 frameOfPresentedViewInContainerView
        let presentedViewControllerFrame = containerView.bounds
            .with {
                $0.origin.y = containerView.bounds.maxY - size.height
                $0.size = size
            }
        
        return presentedViewControllerFrame
    }
    

    #warning(
    """
    屏幕旋转时，dimmingView 和 presentedViewController 的位置发生了错乱，因为没有设置 autoresizingMask
    
    此处可以重新对 UI 进行布局
    """)
    override func containerViewWillLayoutSubviews() {
        super.containerViewWillLayoutSubviews()
        dimmingView?.frame = containerView?.frame ?? .zero
        presentationWrappingView?.frame = frameOfPresentedViewInContainerView
    }
    
    override func preferredContentSizeDidChange(forChildContentContainer container: UIContentContainer) {
        super.preferredContentSizeDidChange(forChildContentContainer: container)

        if let viewController = container as? UIViewController,
            viewController == self.presentedViewController {
            containerView?.setNeedsLayout()
        }
    }
}

extension CustomPresentationController: UIViewControllerAnimatedTransitioning {
    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        #warning("此处需要判断 transitionContext?.isAnimated， isAnimated 是受什么影响的？")
        return transitionContext?.isAnimated ?? false ? 0.35 : 0
    }
    
    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        guard let toViewController = transitionContext.viewController(forKey: .to),
              let fromViewController = transitionContext.viewController(forKey: .from) else {
                  let wasCancelled = transitionContext.transitionWasCancelled
                  transitionContext.completeTransition(!wasCancelled)
                  return
              }
        let fromeViewInitialFrame = transitionContext.initialFrame(for: fromViewController)
        let toViewFinalFrame = transitionContext.finalFrame(for: toViewController)
        
        let toView = transitionContext.view(forKey: .to)
        transitionContext.view(forKey: .from)?
            .do {
                $0.frame = fromeViewInitialFrame
            }
        let containerView = transitionContext.containerView
        let isPresentation = toViewController.presentingViewController == fromViewController
        
        
        if isPresentation {
            if let toView = toView {
                toView.frame = toViewFinalFrame.offsetBy(dx: 0,
                                                         dy: toViewFinalFrame.height)
                containerView.addSubview(toView)
            }
        } else {
            
        }
        let transitionDuration = transitionDuration(using: transitionContext)
        UIView.animate(withDuration: transitionDuration) {
            if isPresentation {
                toView?.frame = toViewFinalFrame
            } else {
                toView?.frame = toViewFinalFrame
            }
        } completion: { finished in
            let wasCancelled = transitionContext.transitionWasCancelled
            transitionContext.completeTransition(!wasCancelled)
        }

    }
}


extension CustomPresentationController: UIViewControllerTransitioningDelegate {
    
    func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return self
    }
    
    func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return self
    }
    
    func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
        return self
    }
}
